package com.ccrfid.rmc6.service.mattress;

import com.ccrfid.rmc6.appconfig.websocket.MattressWebSocketHandler;
import com.ccrfid.rmc6.entity.mattress.BedAlarmEntity;
import com.ccrfid.rmc6.entity.mattress.BedAlarmView;
import com.ccrfid.rmc6.entity.mattress.BedEntity;
import com.ccrfid.rmc6.entity.mattress.MattressStateEntity;
import com.ccrfid.rmc6.pojo.Constants;
import com.ccrfid.rmc6.repository.mattress.BedAlarmRepository;
import com.ccrfid.rmc6.repository.mattress.BedAlarmViewRepository;
import com.ccrfid.rmc6.repository.mattress.BedRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.transaction.Transactional;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingDeque;

@Service
@Transactional
public class MattressAlarmServiceImpl implements MattressAlarmService {
    private static final Logger logger = LoggerFactory.getLogger(MattressDataReceiver.class);

    private BlockingQueue<MattressStateEntity> mattressStateQueue;
    private Map<String, AlarmFlag> alarmFlagMap;

    @Autowired
    private BedRepository bedRepository;
    @Autowired
    private BedAlarmRepository bedAlarmRepository;
    @Autowired
    private BedAlarmViewRepository bedAlarmViewRepository;
    @Autowired
    private MattressWebSocketHandler mattressWebSocketHandler;

    //床垫告警持续时间
    @Value("${ht.alarm.delay.time}")
    private Integer timeDelay;
    //允许的最大/最小呼吸频率
    @Value("${ht.alarm.breath.rate.min}")
    private Integer minBreathRate;
    @Value("${ht.alarm.breath.rate.max}")
    private Integer maxBreathRate;
    //允许的最大/最小心率
    @Value("${ht.alarm.heart.rate.min}")
    private Integer minHeartRate;
    @Value("${ht.alarm.heart.rate.max}")
    private Integer maxHeartRate;

    public MattressAlarmServiceImpl() {
        this.mattressStateQueue = new LinkedBlockingDeque<>(1024 * 8);
        this.alarmFlagMap = new ConcurrentHashMap<>();
    }

    @PostConstruct
    private void init() {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        MattressStateEntity mattressState = mattressStateQueue.take();
                        //触发告警
                        triggerAlarm(mattressState);

                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        });
        thread.start();
    }

    public boolean inputMattressState(MattressStateEntity mattressState) {
        return mattressStateQueue.offer(mattressState);
    }

    public void triggerAlarm(MattressStateEntity mattressState) {
        if (mattressState.getState() == Constants.BED_STATE.OFF.id) {
            //离床状态不触发告警
            return;
        }
        if (!alarmFlagMap.containsKey(mattressState.getMattressSn())) {
            alarmFlagMap.put(mattressState.getMattressSn(), new AlarmFlag());
        }
        AlarmFlag alarmFlag = alarmFlagMap.get(mattressState.getMattressSn());
        //1.心率过低告警
        handleLowHeartRateAlarm(alarmFlag.getLowHeartFlag(), mattressState);
        //2.心率过高告警
        handleHighHeartRateAlarm(alarmFlag.getHighHeartFlag(), mattressState);
        //3.呼吸频率过低告警
        handleLowBreathRateAlarm(alarmFlag.getLowBreathFlag(), mattressState);
        //4.呼吸急促告警
        handleHighBreathRateAlarm(alarmFlag.getHighBreathFlag(), mattressState);
    }

    private void postAlarmRemoveMsg(MattressStateEntity mattressState, Integer alarmType) {
        BedEntity bedEntity = bedRepository.getByMattressSn(mattressState.getMattressSn());
        if (bedEntity != null) {
            BedAlarmView bedAlarm = new BedAlarmView();
            bedAlarm.setAlarmType(alarmType);
            bedAlarm.setBedSn(bedEntity.getBedSn());
            bedAlarm.setMattressSn(bedEntity.getMattressSn());
            bedAlarm.setPersonnelId(bedEntity.getPersonnelId());
            bedAlarm.setPersonnelName(bedEntity.getPersonnelName());
            bedAlarm.setMattressSn(mattressState.getMattressSn());
            bedAlarm.setState(mattressState.getState());
            bedAlarm.setBreathRate(mattressState.getBreathRate());
            bedAlarm.setHeartRate(mattressState.getHeartRate());
            bedAlarm.setWeight(mattressState.getWeight());
            bedAlarm.setWet(mattressState.getWet());
            bedAlarm.setSleepState(mattressState.getSleepState());
            bedAlarm.setRecordTime(mattressState.getRecordTime());
            //
            mattressWebSocketHandler.inputBedAlarm(bedAlarm);
        }
    }

    private void handleLowHeartRateAlarm(Flag flag, MattressStateEntity mattressState) {
        Integer heartRate = mattressState.getHeartRate();
        if (heartRate < minHeartRate) {
            //触发告警
            if (flag.triggered) {
                //ignore，重复告警
            } else {
                if (flag.getFirstTime() == 0) {
                    flag.setFirstTime(mattressState.getRecordTime().getTime());
                } else {
                    if (mattressState.getRecordTime().getTime() - flag.getFirstTime() > timeDelay) {
                        //产生告警
                        BedEntity bedEntity = bedRepository.getByMattressSn(mattressState.getMattressSn());
                        if (bedEntity != null) {
                            BedAlarmEntity bedAlarmEntity = new BedAlarmEntity();
                            bedAlarmEntity.setAlarmType(Constants.BED_ALARM_TYPE.HEART_LOW.id);
                            bedAlarmEntity.setBedSn(bedEntity.getBedSn());
                            bedAlarmEntity.setMattressSn(bedEntity.getMattressSn());
                            bedAlarmEntity.setPersonnelId(bedEntity.getPersonnelId());
                            bedAlarmEntity.setPersonnelName(bedEntity.getPersonnelName());
                            bedAlarmEntity.setMattressStateId(mattressState.getId());
                            bedAlarmRepository.save(bedAlarmEntity);

                            BedAlarmView bedAlarm = bedAlarmViewRepository.getById(bedAlarmEntity.getId());
                            mattressWebSocketHandler.inputBedAlarm(bedAlarm);
                        }
                        //设置告警标识
                        flag.setTriggered(true);
                    }
                }
            }
        } else {
            //解除告警
            if (flag.isTriggered()) {
                postAlarmRemoveMsg(mattressState, Constants.BED_ALARM_TYPE.HEART_LOW_REMOVE.id);
            }
            flag.setTriggered(false);
            flag.setFirstTime(0);
        }
    }

    private void handleHighHeartRateAlarm(Flag flag, MattressStateEntity mattressState) {
        Integer heartRate = mattressState.getHeartRate();
        if (heartRate > maxHeartRate) {
            //触发告警
            if (flag.triggered) {
                //ignore，重复告警
            } else {
                if (flag.getFirstTime() == 0) {
                    flag.setFirstTime(mattressState.getRecordTime().getTime());
                } else {
                    if (mattressState.getRecordTime().getTime() - flag.getFirstTime() > timeDelay) {
                        //产生告警
                        BedEntity bedEntity = bedRepository.getByMattressSn(mattressState.getMattressSn());
                        if (bedEntity != null) {
                            BedAlarmEntity bedAlarmEntity = new BedAlarmEntity();
                            bedAlarmEntity.setAlarmType(Constants.BED_ALARM_TYPE.HEART_HIGH.id);
                            bedAlarmEntity.setBedSn(bedEntity.getBedSn());
                            bedAlarmEntity.setMattressSn(bedEntity.getMattressSn());
                            bedAlarmEntity.setPersonnelId(bedEntity.getPersonnelId());
                            bedAlarmEntity.setPersonnelName(bedEntity.getPersonnelName());
                            bedAlarmEntity.setMattressStateId(mattressState.getId());
                            bedAlarmRepository.save(bedAlarmEntity);

                            BedAlarmView bedAlarm = bedAlarmViewRepository.getById(bedAlarmEntity.getId());
                            mattressWebSocketHandler.inputBedAlarm(bedAlarm);
                        }
                        //设置告警标识
                        flag.setTriggered(true);
                    }
                }
            }
        } else {
            //解除告警
            if (flag.isTriggered()) {
                postAlarmRemoveMsg(mattressState, Constants.BED_ALARM_TYPE.HEART_HIGH_REMOVE.id);
            }
            flag.setTriggered(false);
            flag.setFirstTime(0);
        }
    }

    private void handleLowBreathRateAlarm(Flag flag, MattressStateEntity mattressState) {
        Integer breathRate = mattressState.getBreathRate();
        if (breathRate < minBreathRate) {
            //触发告警
            if (flag.triggered) {
                //ignore，重复告警
            } else {
                if (flag.getFirstTime() == 0) {
                    flag.setFirstTime(mattressState.getRecordTime().getTime());
                } else {
                    if (mattressState.getRecordTime().getTime() - flag.getFirstTime() > timeDelay) {
                        //产生告警
                        BedEntity bedEntity = bedRepository.getByMattressSn(mattressState.getMattressSn());
                        if (bedEntity != null) {
                            BedAlarmEntity bedAlarmEntity = new BedAlarmEntity();
                            bedAlarmEntity.setAlarmType(Constants.BED_ALARM_TYPE.BREATH_LOW.id);
                            bedAlarmEntity.setBedSn(bedEntity.getBedSn());
                            bedAlarmEntity.setMattressSn(bedEntity.getMattressSn());
                            bedAlarmEntity.setPersonnelId(bedEntity.getPersonnelId());
                            bedAlarmEntity.setPersonnelName(bedEntity.getPersonnelName());
                            bedAlarmEntity.setMattressStateId(mattressState.getId());
                            bedAlarmRepository.save(bedAlarmEntity);

                            BedAlarmView bedAlarm = bedAlarmViewRepository.getById(bedAlarmEntity.getId());
                            mattressWebSocketHandler.inputBedAlarm(bedAlarm);
                        }
                        //设置告警标识
                        flag.setTriggered(true);
                    }
                }
            }
        } else {
            //解除告警
            if (flag.isTriggered()) {
                postAlarmRemoveMsg(mattressState, Constants.BED_ALARM_TYPE.BREATH_LOW_REMOVE.id);
            }
            flag.setTriggered(false);
            flag.setFirstTime(0);
        }
    }

    private void handleHighBreathRateAlarm(Flag flag, MattressStateEntity mattressState) {
        Integer breathRate = mattressState.getBreathRate();
        if (breathRate > maxBreathRate) {
            //触发告警
            if (flag.triggered) {
                //ignore，重复告警
            } else {
                if (flag.getFirstTime() == 0) {
                    flag.setFirstTime(mattressState.getRecordTime().getTime());
                } else {
                    if (mattressState.getRecordTime().getTime() - flag.getFirstTime() > timeDelay) {
                        //产生告警
                        BedEntity bedEntity = bedRepository.getByMattressSn(mattressState.getMattressSn());
                        if (bedEntity != null) {
                            BedAlarmEntity bedAlarmEntity = new BedAlarmEntity();
                            bedAlarmEntity.setAlarmType(Constants.BED_ALARM_TYPE.BREATH_HIGH.id);
                            bedAlarmEntity.setBedSn(bedEntity.getBedSn());
                            bedAlarmEntity.setMattressSn(bedEntity.getMattressSn());
                            bedAlarmEntity.setPersonnelId(bedEntity.getPersonnelId());
                            bedAlarmEntity.setPersonnelName(bedEntity.getPersonnelName());
                            bedAlarmEntity.setMattressStateId(mattressState.getId());
                            bedAlarmRepository.save(bedAlarmEntity);

                            BedAlarmView bedAlarm = bedAlarmViewRepository.getById(bedAlarmEntity.getId());
                            mattressWebSocketHandler.inputBedAlarm(bedAlarm);
                        }
                        //设置告警标识
                        flag.setTriggered(true);
                    }
                }
            }
        } else {
            //解除告警
            if (flag.isTriggered()) {
                postAlarmRemoveMsg(mattressState, Constants.BED_ALARM_TYPE.BREATH_HIGH_REMOVE.id);
            }
            flag.setTriggered(false);
            flag.setFirstTime(0);
        }
    }

    private class AlarmFlag {
        private Flag lowHeartFlag;
        private Flag highHeartFlag;
        private Flag lowBreathFlag;
        private Flag highBreathFlag;

        public AlarmFlag() {
            this.lowHeartFlag = new Flag();
            this.highHeartFlag = new Flag();
            this.lowBreathFlag = new Flag();
            this.highBreathFlag = new Flag();
        }

        public Flag getLowHeartFlag() {
            return lowHeartFlag;
        }

        public void setLowHeartFlag(Flag lowHeartFlag) {
            this.lowHeartFlag = lowHeartFlag;
        }

        public Flag getHighHeartFlag() {
            return highHeartFlag;
        }

        public void setHighHeartFlag(Flag highHeartFlag) {
            this.highHeartFlag = highHeartFlag;
        }

        public Flag getLowBreathFlag() {
            return lowBreathFlag;
        }

        public void setLowBreathFlag(Flag lowBreathFlag) {
            this.lowBreathFlag = lowBreathFlag;
        }

        public Flag getHighBreathFlag() {
            return highBreathFlag;
        }

        public void setHighBreathFlag(Flag highBreathFlag) {
            this.highBreathFlag = highBreathFlag;
        }
    }

    private class Flag {
        private boolean triggered;
        private long firstTime;

        public Flag() {
            this.triggered = false;
            this.firstTime = 0;
        }

        public boolean isTriggered() {
            return triggered;
        }

        public void setTriggered(boolean triggered) {
            this.triggered = triggered;
        }

        public long getFirstTime() {
            return firstTime;
        }

        public void setFirstTime(long firstTime) {
            this.firstTime = firstTime;
        }
    }
}
